package com.ztesoft.zsmart.zcm.monitor.utils;

import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import com.ztesoft.zsmart.core.log.ZSmartLogger;
import com.ztesoft.zsmart.zcm.monitor.config.MonitorProperties;

import redis.clients.jedis.Jedis;

@Component
public final class RedisUtil {
    private final ZSmartLogger logger = ZSmartLogger.getLogger(RedisUtil.class);

    private Integer keyExpireTime;

    @Resource
    private RedisTemplate redisTemplate;

    private RedisUtil() {
    }

    public Long ttl(byte[] key) {
        return (Long) redisTemplate.execute((RedisCallback<Long>) redisConnection -> {
            Jedis jedis = (Jedis) redisConnection.getNativeConnection();
            return jedis.ttl(key);
        });
    }

    public void expire(byte[] key, Integer timeout) {
        redisTemplate.execute((RedisCallback<Long>) redisConnection -> {
            Jedis jedis = (Jedis) redisConnection.getNativeConnection();
            return jedis.expire(key, timeout);
        });
    }

    public void expire(String key, Integer timeout) {
        redisTemplate.execute((RedisCallback<Long>) redisConnection -> {
            Jedis jedis = (Jedis) redisConnection.getNativeConnection();
            return jedis.expire(key, timeout);
        });
    }

    public Map<byte[], byte[]> hgetAll(byte[] key) {
        return (Map<byte[], byte[]>) redisTemplate.execute((RedisCallback<Map<byte[], byte[]>>) redisConnection -> {
            Jedis jedis = (Jedis) redisConnection.getNativeConnection();
            return jedis.hgetAll(key);
        });
    }

    /**
     * hget
     *
     * @param key key
     * @param field field
     */
    public byte[] hget(String key, String field) {
        return (byte[]) redisTemplate.execute((RedisCallback<byte[]>) redisConnection -> {
            Jedis jedis = (Jedis) redisConnection.getNativeConnection();
            return jedis.hget(key.getBytes(), field.getBytes());
        });
    }

    /**
     * hset
     *
     * @param key key
     * @param field field
     * @param t t
     */
    public <T> void hset(String key, String field, T t) {
        redisTemplate.execute((RedisCallback<Object>) redisConnection -> {
            Jedis jedis = (Jedis) redisConnection.getNativeConnection();
            return jedis.hset(key.getBytes(), field.getBytes(), SerializeUtil.serialize(t));
        });
    }

    /**
     * 设置字符串
     *
     * @param key String
     * @param value String
     */
    public void set(String key, String value) {
        redisTemplate.execute((RedisCallback<Object>) redisConnection -> {
            Jedis jedis = (Jedis) redisConnection.getNativeConnection();
            return jedis.set(key, value);
        });
    }

    /**
     * 获取字符串
     *
     * @param key String
     * @return String
     */
    public String get(String key) {
        return (String) redisTemplate.execute((RedisCallback<String>) redisConnection -> {
            Jedis jedis = (Jedis) redisConnection.getNativeConnection();
            return jedis.get(key);
        });
    }

    /**
     * 删除字符串
     *
     * @param key String
     */
    public void del(String key) {
        redisTemplate.execute((RedisCallback<Long>) redisConnection -> {
            Jedis jedis = (Jedis) redisConnection.getNativeConnection();
            return jedis.del(key);
        });
    }

    public void del(byte[] key) {
        redisTemplate.execute((RedisCallback<Long>) redisConnection -> {
            Jedis jedis = (Jedis) redisConnection.getNativeConnection();
            return jedis.del(key);
        });
    }

    /**
     * 添加哈希，设置生存周期
     *
     * @param key byte[]
     * @param field byte[]
     * @param value byte[]
     */
    public void hsetByTTL(byte[] key, byte[] field, byte[] value) {
        redisTemplate.execute((RedisCallback<Object>) redisConnection -> {
            Jedis jedis = (Jedis) redisConnection.getNativeConnection();
            jedis.hset(key, field, value);
            return jedis.expire(key, 6 * 60 * 60);
        });
    }

    /**
     * 添加哈希,存在则不保存
     *
     * @param key byte[]
     * @param field byte[]
     * @param value byte[]
     */
    public void hsetIfNotExists(byte[] key, byte[] field, byte[] value) {
        redisTemplate.execute((RedisCallback<Object>) redisConnection -> {
            Jedis jedis = (Jedis) redisConnection.getNativeConnection();
            if (!jedis.hexists(key, field)) {
                jedis.hset(key, field, value);
            }
            return null;
        });
    }

    /**
     * 添加哈希
     *
     * @param key byte[]
     * @param field byte[]
     * @param value byte[]
     */
    public void hset(byte[] key, byte[] field, byte[] value) {
        redisTemplate.execute((RedisCallback<Object>) redisConnection -> {
            Jedis jedis = (Jedis) redisConnection.getNativeConnection();
            return jedis.hset(key, field, value);
        });
    }

    /**
     * 删除哈希
     *
     * @param key byte[]
     * @param field byte[]
     */
    public void hdel(byte[] key, byte[] field) {
        redisTemplate.execute((RedisCallback<Object>) redisConnection -> {
            Jedis jedis = (Jedis) redisConnection.getNativeConnection();
            return jedis.hdel(key, field);
        });
    }

    public Long hdel(String key, String field) {
        return (Long) redisTemplate.execute((RedisCallback<Long>) redisConnection -> {
            Jedis jedis = (Jedis) redisConnection.getNativeConnection();
            return jedis.hdel(key, field);
        });
    }

    /**
     * 获取全部哈希值
     *
     * @param key byte[]
     * @return List<byte[]>
     */
    public List<byte[]> hvals(byte[] key) {
        return (List<byte[]>) redisTemplate.execute((RedisCallback<List<byte[]>>) redisConnection -> {
            Jedis jedis = (Jedis) redisConnection.getNativeConnection();
            return jedis.hvals(key);
        });
    }

    /**
     * 获取哈希值
     *
     * @param key byte[]
     * @param field byte[]
     * @return byte[]
     */
    public byte[] hget(byte[] key, byte[] field) {
        return (byte[]) redisTemplate.execute((RedisCallback<byte[]>) redisConnection -> {
            Jedis jedis = (Jedis) redisConnection.getNativeConnection();
            return jedis.hget(key, field);
        });
    }

    public void hsetByExpireTime(byte[] key, byte[] field, byte[] value, Integer time) {
        if (keyExpireTime == null) {
            keyExpireTime = SpringContextUtil.getBean(MonitorProperties.class).getJedisKeyExpireTime();
        }
        redisTemplate.execute((RedisCallback<Object>) redisConnection -> {
            Jedis jedis = (Jedis) redisConnection.getNativeConnection();
            jedis.hset(key, field, value);
            if (time != null) {
                return jedis.expire(key, time);
            }
            else {
                return jedis.expire(key, keyExpireTime);
            }
        });
    }

    public Map<byte[], byte[]> hgetByExpireTime(byte[] key) {
        return (Map<byte[], byte[]>) redisTemplate.execute((RedisCallback<Map<byte[], byte[]>>) redisConnection -> {
            Jedis jedis = (Jedis) redisConnection.getNativeConnection();
            return jedis.hgetAll(key);
        });
    }

    public boolean hexists(byte[] key, byte[] field) {
        return (boolean) redisTemplate.execute((RedisCallback<Boolean>) redisConnection -> {
            Jedis jedis = (Jedis) redisConnection.getNativeConnection();
            return jedis.hexists(key, field);
        });
    }

    public Long insr(String key, int seconds) {
        return (Long) redisTemplate.execute((RedisCallback<Long>) redisConnection -> {
            Jedis jedis = (Jedis) redisConnection.getNativeConnection();
            Long incr = jedis.incr(key);
            jedis.expire(key, seconds);
            return incr;
        });
    }
}
